<!--
    卡片风格的文件上传组件，主要用于一些小文件的上传，暂不支持分组上传,
    如果一个页面上有多个该组件实例，需要指定为不同的uploadId

    用法：<f7-file-upload :params="uploadParams" accept="image/png,image/jpeg" extensions="png,jpg,jpeg" title="资质证书" uploadId="files1"></f7-file-upload>

    备注：params，url后的请求参数，JSON格式，比如上面的
                uploadParams = { dataKey: 'xx', type: 'company' }
        accept，接受什么样的文件
        extensions，接受什么样的文件后缀
        title，显示的标题
        uploadId，默认值files，如果一个页面上有多个该组件实例，需要指定为不同的uploadId
 -->
<template>
  <f7-card class="upload-card">
    <f7-card-header class="header">
      <span class="title">{{ title }}</span>
      <span>
        <file-upload
          name="file"
          class="button"
          :input-id="uploadId"
          :uploadAuto="uploadAuto"
          @input-file="inputFile"
          @input-filter="inputFilter"
          :multiple="multiple"
          :data="params"
          :extensions="extensions"
          :accept="accept"
          :size="size"
          :post-action="postUrl"
          v-model="uploadFiles"
          :ref="uploadId"
        >
          <f7-icon f7="plus_circle" class="icon"></f7-icon>
        </file-upload>
      </span>
    </f7-card-header>
    <f7-card-content>
      <f7-list media-list>
        <div
          class="list-item"
          v-for="(file, index) in uploadFiles"
          :key="file.id || file.attachmentId"
        >
          <f7-list-item style="padding-left: 0" class="content">
            <template v-if="Object.keys(file).includes('response')">
              <div v-if="file.response" slot="title" class="filename">
                {{
                  file.name.lastIndexOf(".") == -1 ? file.name + ext : file.name
                }}
              </div>
              <img
                v-if="file.response"
                slot="media"
                :src="getThumb(file) | mapStatic"
                width="40"
              />
              <div v-if="file.response" slot="text" class="text">
                <span>{{ file.size | fileSize }}</span>
                <span class="right text-color-red" v-if="file.error">{{
                  formatError(file)
                }}</span>
                <span class="right" v-else-if="file.active"
                  >{{ file.progress }}%</span
                >
                <span
                  class="right"
                  v-else-if="file.response && file.response.success"
                  >上传成功</span
                >
                <span
                  class="right"
                  v-else-if="file.response && !file.response.success"
                  >上传失败</span
                >
                <span class="right" v-else>等待中...</span>
              </div>
              <f7-progressbar
                v-if="file.response"
                slot="subtitle"
                color="linear-gradient(117deg, #62BBFF 0%, #3385FF 100%)"
                :progress="parseFloat(file.progress)"
              ></f7-progressbar>
            </template>
            <template v-else>
              <div v-if="file.attachmentId" slot="title" class="filename">
                {{ file.fileName }}
              </div>
              <img
                v-if="file.attachmentId"
                slot="media"
                :src="getThumbPng(file.fileType) | mapStatic"
                width="40"
              />
              <div v-if="file.attachmentId" slot="text"  class="text">
                <span>{{ file.fileSize | fileSize }}</span>
              </div>
            </template>
          </f7-list-item>
          <span class="operation" @click="operate(file, index)"
            ><f7-icon f7="xmark" class="operation-icon"></f7-icon
          ></span>
        </div>
      </f7-list>
    </f7-card-content>
  </f7-card>
</template>
<script>
import ImageCompressor from "image-compressor.js";
import FileUpload from "vue-upload-component";
import formatter from "../../framework/formatter";
import Config from "../../config";
import Upload from "../../framework/upload";

export default {
  components: {
    FileUpload,
  },
  props: {
    params: {
      type: Object,
      default: {},
    },
    extensions: {
      type: String,
      default: "",
    },
    accept: {
      type: String,
      default: "",
    },
    multiple: {
      type: Boolean,
      default: true,
    },
    size: {
      type: Number,
      default: 1024 * 1024 * 10,
    },
    chunkAction: {
      type: String,
      default: "/api/base/ChunkUpload/upload",
    },
    uploadAuto: {
      type: Boolean,
      default: true,
    },
    title: {
      type: String,
      default: "",
    },
    uploadId: {
      type: String,
      default: "file",
    },
    initFile: {
      type: Object,
    },
  },
  data() {
    return {
      downUrl: "/api/base/fileupload/downFile",
      getUrl: "/api/base/fileupload/getFiles",
      deleteUrl: "/api/base/fileupload/delFile",
      postUrl: "/api/base/fileupload/uploadFile",
      ext: "",
      uploadFiles: [],
      actionTitle: "",
      actionFileKey: "",
      operateFileIndex: null,
    };
  },
  methods: {
    operate(file, index) {
      let self = this;

      if (
        file.attachmentId ||
        (file.response && file.response.parameters.file)
      ) {
        self.actionFileKey = file.attachmentId;
        self.actionTitle = file.fileName;
        if (!self.actionFileKey) {
          let respFile = file.response.parameters.file;
          self.actionFileKey = respFile.key;
          self.actionTitle = file.name;
        }

        self.operateFileIndex = index;
      } else {
        self.$f7.dialog.alert(
          "文件" + file.name + "没有上传成功，无法操作",
          function () {
            self.uploadFiles.splice(self.operateFileIndex, 1);
          }
        );
        return;
      }

      self.$f7.actions
        .create({
          buttons: [
            {
              text: self.actionTitle,
              label: true,
            },
            {
              text: "删除",
              color: "red",
              onClick: function () {
                self.$f7.dialog.confirm("确定要删除该文件吗？", "删除", () => {
                  // 文件可能因类型不符合而没有成功上传，此时直接从页面上删除
                  if (!self.actionFileKey) {
                    self.$f7.dialog.toast("删除成功");
                    self.uploadFiles.splice(self.operateFileIndex, 1);
                    return;
                  }
                  self.$f7.preloader.show();
                  self.$f7.request.post(
                    Config.api.delFile,
                    { attachmentId: self.actionFileKey },
                    (r) => {
                      r = JSON.parse(r);
                      self.$f7.preloader.hide();
                      if (r && r.success) {
                        self.uploadFiles.splice(self.operateFileIndex, 1);
                        self.$f7.dialog.toast("删除成功");
                      } else {
                        self.$f7.dialog.toast(r.message || "删除失败");
                      }
                    }
                  );
                });
              },
            },
          ],
        })
        .open();
    },
    getThumb(file) {
      let i = file.name.lastIndexOf(".");
      if (i != -1) {
        let extension = file.name.substring(i);
        return this.getThumbPng(extension);
      }
      if (this.ext) {
        return (
          "/static/img/file/" + this.ext.substr(1, this.ext.length) + ".png"
        );
      }
      return "/static/img/file/default.png";
    },
    getThumbPng(fileExt) {
      if (
        fileExt &&
        ".avi,.doc,.docx,.jpg,.mp4,.pdf,.png,.ppt,.pptx,.rar,.txt,.xls,.xlsx,.zip"
          .split(",")
          .includes(fileExt.toLowerCase())
      ) {
        return "/static/img/file/" + fileExt.toLowerCase().substr(1) + ".png";
      }
      if (this.ext) {
        return (
          "/static/img/file/" + this.ext.substr(1, this.ext.length) + ".png"
        );
      }
      return "/static/img/file/default.png";
    },
    formatError(file) {
      var error = "上传失败";
      switch (file.error) {
        case "size":
          error = "文件太大，不超过" + formatter.formatFileSize(this.size);
          break;
        case "extension":
          error = "文件类型不符，只允许" + this.accept;
          break;
        case "timeout":
          error = "网络超时";
          break;
        case "abort":
          error = "用户放弃";
          break;
        case "network":
          error = "网络连接失败";
          break;
        case "server":
          error = "服务器错误";
          break;
        case "denied":
          error = "请求无效";
          break;
        default:
          error = "上传失败";
          break;
      }
      return error;
    },
    inputFilter(newFile, oldFile, prevent) {
      if (newFile && !oldFile) {
        let self = this;
        let name = newFile.file.name;

        if (newFile.file.type == "" && window.FileReader) {
          var reader = new FileReader();
          reader.addEventListener("load", function (e) {
            var typesMap = {
              doc: "d0 cf 11 e0 a1 b1 1a e1",
              docx: "50 4b 03 04",
              pdf: "25 50 44 46",
            };

            var arrayBuffer = e.target.result;
            if (arrayBuffer && arrayBuffer.byteLength >= 4) {
              var slice = arrayBuffer.slice(0, 4);
              var view = new Uint8Array(slice);
              var arr = [];
              view.forEach(function (v) {
                arr.push(v.toString(16));
              });
              if (typesMap.doc.indexOf(arr.join(" ")) != -1) {
                self.ext = ".doc";
              }
              if (typesMap.docx.indexOf(arr.join(" ")) != -1) {
                self.ext = ".docx";
              }
              if (typesMap.pdf.indexOf(arr.join(" ")) != -1) {
                self.ext = ".pdf";
              }
            }
          });

          reader.readAsArrayBuffer(newFile.file);
        }
        // Before adding a file
        // 添加文件前
        // Filter system files or hide files
        // 过滤系统文件 和隐藏文件
        if (/(\/|^)(Thumbs\.db|desktop\.ini|\..+)$/.test(newFile.name)) {
          return prevent();
        }
        // Filter php html js file
        // 过滤 php html js 文件
        if (/\.(php5?|html?|jsx?)$/i.test(newFile.name)) {
          return prevent();
        }
        // Automatic compression
        // 自动压缩
        if (
          newFile.file &&
          newFile.type.substr(0, 6) === "image/" &&
          this.autoCompress > 0 &&
          this.autoCompress < newFile.size
        ) {
          newFile.error = "compressing";
          const imageCompressor = new ImageCompressor(null, {
            convertSize: Infinity,
            maxWidth: 512,
            maxHeight: 512,
          });
          imageCompressor
            .compress(newFile.file)
            .then((file) => {
              this.$refs[this.uploadId].update(newFile, {
                error: "",
                file,
                size: file.size,
                type: file.type,
              });
            })
            .catch((err) => {
              this.$refs[this.uploadId].update(newFile, {
                error: err.message || "compress",
              });
            });
        }
      }
      if (newFile && (!oldFile || newFile.file !== oldFile.file)) {
        // Create a blob field
        // 创建 blob 字段
        newFile.blob = "";
        let URL = window.URL || window.webkitURL;
        if (URL && URL.createObjectURL) {
          newFile.blob = URL.createObjectURL(newFile.file);
        }
        // Thumbnails
        // 缩略图
        newFile.thumb = "";
        if (newFile.blob && newFile.type.substr(0, 6) === "image/") {
          newFile.thumb = newFile.blob;
        }
      }
    },
    // add, update, remove File Event
    inputFile(newFile, oldFile) {
      if (newFile && oldFile) {
        // update
        if (newFile.active && !oldFile.active) {
          // beforeSend
          // min size
          if (
            newFile.size >= 0 &&
            this.minSize > 0 &&
            newFile.size < this.minSize
          ) {
            this.$refs[this.uploadId].update(newFile, { error: "size" });
          }
        }
        if (newFile.progress !== oldFile.progress) {
          // progress
        }
        if (newFile.error && !oldFile.error) {
          // error
          this.$f7.dialog.toast("文件上传失败");
        }
        if (newFile.success && !oldFile.success) {
          // success
          let rep = newFile.response;
          if (Object.keys(rep).includes("success") && rep.success) {
            // 上传成功
            this.$emit("success", newFile);
            // this.$f7.dialog.toast(`文件上传成功`);
          } else {
            // 上传失败
            this.$f7.dialog.alert(
              newFile.response.message || "服务器不允许该文件上传"
            );
            this.uploadFiles.pop();
          }
        }
        // if (newFile.success && !oldFile.success) {
        //   // success
        //   let fs = newFile.response.files;
        //   if (fs && fs[0].error) {
        //     this.$f7.dialog.toast(`${fs[0].message}`);
        //     let ind = this.uploadFiles.findIndex(f => {
        //       return f.id && f.id == newFile.id;
        //     });
        //     if (ind != -1) {
        //       this.uploadFiles.splice(ind, 1);
        //     }
        //   } else {
        //     this.$emit("success", newFile);
        //     this.$f7.dialog.toast(`文件上传成功`);
        //   }
        // }
      }
      if (!newFile && oldFile) {
        // remove
        if (oldFile.success && oldFile.response.id) {
          // $.ajax({
          //   type: 'DELETE',
          //   url: '/upload/delete?id=' + oldFile.response.id,
          // })
        }
      }
      // Automatically activate upload
      if (
        Boolean(newFile) !== Boolean(oldFile) ||
        oldFile.error !== newFile.error
      ) {
        if (this.uploadAuto && !this.$refs[this.uploadId].active) {
          this.$refs[this.uploadId].active = true;
        }
      }
    },
  },
  created() {
    // 打包时不需要
    // this.getUrl = Config.api.getUrl;
    this.$f7.request.post(this.getUrl, this.params, (r) => {
      r = JSON.parse(r);
      if (r && r.success) {
        this.uploadFiles = r.parameters.files || [];
      } else {
        this.$framework.$f7.dialog.toast("获取文件失败");
      }
    });
  },
  mounted() {
    if (window.plus) {
      this.postUrl = Config.api.upload;
    }
    if (this.initFile) {
      this.filesJson[this.uploadId].push(this.initFile);
    }
  },
};
</script>
<style scoped>
.upload-card{
  margin: 0px;
  padding: 0px;
  --f7-card-border-radius:0px;
  box-shadow:none
}
.chunk-loading {
  margin: -12px;
  display: flex;
  width: calc(100% + 24px);
}
.chunk-loading .chunk-loading-part {
  height: 25px;
  line-height: 25px;
  flex: 1;
  background: #ccc;
  font-size: 14px;
  color: white;
  text-align: center;
}
.chunk-loading .chunk-loading-part.chunk-loading-part__uploaded {
  background: #28a745;
}
.file-uploads {
  width: 160%;
}

/* *************************** */
.header {
  /* padding: 0; */
  padding: 0 calc(40px * var(--ratio));
}

.header::after {
  display: none;
}

.title {
  font-size: var(--font-size-maincontent);
  color: var(--color-text-main);
}

.icon {
  font-size: calc(42px * var(--ratio));
  color: #242424;
}

.progressbar {
  margin-top: calc(14px * var(--ratio));
}

.text {
  display: flex;
  justify-content: space-between;
  margin-top: calc(12px * var(--ratio));
  font-size: var(--font-size-subcontent-2);
  color: var(--color-text-subtext);
}

.list-item {
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-right: 16px;
}

.content {
  flex: 1;
}

/* .content >>> .item-inner::after {
  display: none !important;
} */

.filename{
    font-size: var(--font-size-subcontent);
    color: var(--color-text-title);
}

.operation {
  display: inline-block;
  position: relative;
  width: calc(54px * var(--ratio));
  height: calc(54px * var(--ratio));
  border-radius: 50%;
  background: #e7f1ffb2;
}

.operation-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>
